#ifndef xpack_lang_cxx_encode_first_as
#define xpack_lang_cxx_encode_first_as
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::lang_cxx::inc
#include"define/base_type.hpp"
#include"lang/cxx.hpp"
#include"lang/wxx/length_if_as_utf8.hpp"
#include"lang/wxx.hpp"
#include"meta/is_base_char.hpp"
#include"meta/unsigned_type.hpp"
#include"meta/is_same.hpp"
#pragma pop_macro("xuser")

namespace mixc::lang_cxx{
    enum encode_first_as_result_t{
        success,
        char_seqence_missing,
        overflow,
        narrow,
    };

    template<inc::is_base_char item_t>
    xstruct(
        xtmpl(encode_first_as_result, item_t)
    )
    public:
        xprops()
            // 当前 item_t 格式字符长度是多少，对于 char16_t, char32_t 始终是 1，该参数只对 item 为 char 的多字节字符有用
            xpubget(length, uxx);
            xpubget(skip_to_next, uxx); // 原串通过加上这个偏移指向下一个字符

            xpubgetx(is_success, bool){
                xr{ return xthe.m_state == encode_first_as_result_t::success; }
            };

            xpubgetx(is_char_seqence_missing, bool){
                xr{ return xthe.m_state == encode_first_as_result_t::char_seqence_missing; }
            };

            xpubgetx(is_overflow, bool){
                xr{ return xthe.m_state == encode_first_as_result_t::overflow; }
            };

            xpubgetx(is_narrow, bool){
                xr{ return xthe.m_state == encode_first_as_result_t::narrow; }
            };
        $

        xprops_operator()

    public:
        encode_first_as_result(encode_first_as_result_t value, uxx skip_to_next) :
            c08{0},
            m_length(0),
            m_skip_to_next(u08(skip_to_next)),
            m_state(u08(value)){
        }

        encode_first_as_result(item_t const * value, uxx length, uxx skip_to_next) :
            c08{0},
            m_length(u08(length)),
            m_skip_to_next(u08(skip_to_next)),
            m_state(u08(encode_first_as_result_t::success)){

            for(uxx i = 0; i < length; i++){
                xthe[i] = value[i];
            }
        }

        operator item_t &(){
            return xthe[0];
        }

        item_t * ptr(){
            return (item_t *)xthe.c08;
        }

        item_t & operator[](uxx index){
            return ((item_t *)xthe.c08)[index];
        }

    private:
        union{
            char        c08[7];
            char16_t    c16;
            char32_t    c32;
        };

        u08 m_length        : 3;
        u08 m_skip_to_next  : 3;
        u08 m_state         : 2;
    $
}

namespace mixc::lang_cxx{
    template<class item_t>
    template<inc::is_base_char char_t>
    inline encode_first_as_result<char_t> cxx<item_t>::encode_first_as() const {
        // 从 byte1 开始每个字节只有 6bit 是有效的
        // bytes    range                   byte0    byte1    byte2    byte3    byte4    byte5
        // 1        0000 0000 - 0000 007F   0xxxxxxx
        // 2        0000 0080 - 0000 07FF   110xxxxx 10xxxxxx
        // 3        0000 0800 - 0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
        // 4        0001 0000 - 0010 FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
        // 5        0020 0000 - 03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
        // 6        0400 0000 - 7FFF FFFF   1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 
        using result_t      = encode_first_as_result<char_t>;
        auto        word    = inc::unsigned_type<item_t>(xthe[0]);
        char32_t    w32     = 0;
        uxx         length  = 1;

        if constexpr (inc::is_same<item_t, char>){
            // length 表示将当前字符编码成 utf8 字符所需的字节数
            if (length = inc::wxx<item_t>(xthe[0])->length_if_as_utf8;
                length > xthe->length){
                return result_t(encode_first_as_result_t::char_seqence_missing, length);
            }

            if constexpr (sizeof(char_t) == 1){
                return result_t(& xthe[0], length, length);
            }

            if (length == 1){
                w32 = char32_t((u32)word);
            }
            else{
                u08 rest_bits = u08(length - 1) * 6/*utf-8 剩余的每个字节实际有效位数*/;
                u08 first_bits = u08(7 - length);
                u08 mask = u08((1 << first_bits) - 1);
                w32 = char32_t(u08(word) & mask) << rest_bits;

                for(uxx i = 1; i < length; i++){
                    rest_bits -= 6;
                    w32 |= char32_t(u08(xthe[i] & 0x3f)) << rest_bits;
                }
            }

            if constexpr (sizeof(char_t) == 2){
                if (w32 > 0xffff){
                    return result_t(encode_first_as_result_t::overflow, length);
                }

                char16_t value = char16_t(w32);
                return result_t(& value, 1, length);
            }

            if constexpr (sizeof(char_t) == 4){
                return result_t(& w32, 1, length);
            }
            else{
                static_assert(sizeof(char_t) < 4);
                return result_t{nullptr, 1, length};
            }
        }
        // 宽字节字符转单字节字符
        else if constexpr (inc::is_same<char_t, char> and sizeof(item_t) >= 2){
            char buffer[8] = {0};
            length = inc::wxx<item_t>(word)->length_if_as_utf8;
            
            if (length == 1){
                buffer[0] = char(word);
                return result_t(buffer, 1, 1);
            }

            u08 rest_bits = u08(length - 1) * 6;
            u08 first_bits = u08(7 - length);
            u08 prefix = u08(u08(-2) << first_bits);
            buffer[0] = prefix | (word >> rest_bits);

            for(uxx i = length; i-- > 1;){
                buffer[i] = (word & 0x3f) | 0x80;
                word >>= 6;
            }

            return result_t(buffer, length, 1);
        }
        // 宽字符间转换
        else {
            // 宽度一致
            if constexpr (inc::is_same<item_t, char_t>){
                auto value = char_t(word);
                return result_t(& value, 1, 1);
            }
            // 宽化
            else if constexpr (inc::is_same<item_t, char16_t>){
                auto value = char32_t(word);
                return result_t(& value, 1, 1);
            }
            // 窄化
            else if (word > 0xffff){
                return result_t(encode_first_as_result_t::narrow, 1);
            }
            else{
                auto value = char16_t(word);
                return result_t(& value, 1, 1);
            }
        }
    }
}

#endif

xexport(mixc::lang_cxx::encode_first_as_result)
xexport(mixc::lang_cxx::encode_first_as_result_t)
